package org.dark.fund.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.dark.fund.api.AccessTokenService;
import org.dark.fund.api.TokenCacheService;
import org.dark.fund.enums.ResultCode;
import org.dark.fund.exceptions.FundBizException;
import org.dark.fund.api.model.AccessToken;
import org.dark.fund.utils.EncryptUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

@Slf4j
@Service
public class AccessTokenServiceImpl implements AccessTokenService {

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    @Resource
    TokenCacheService<AccessToken> tokenCacheService;

    @Value("${token.expire.time:100}")
    long expireTime;

    @Override
    public AccessToken createToken(String userId) {
        long currentTime = DateUtil.current();
        String tokenStr = EncryptUtil.encrypt(userId) + "|" + UUID.randomUUID();
        AccessToken token = AccessToken.builder()
                .userId(userId)
                .createTime(currentTime)
                .expiryTime(currentTime + expireTime * 1000)
                .lastAccessTime(currentTime)
                .token(tokenStr)
                .build();
        tokenCacheService.put(tokenStr, token);
        return token;
    }

    @Override
    public AccessToken touchToken(String token) {
        AccessToken accessToken = checkToken(token);
        long currentTime = DateUtil.current();
        accessToken.setLastAccessTime(currentTime);
        accessToken.setExpiryTime(currentTime + expireTime * 1000);
        tokenCacheService.put(token, accessToken);
        return accessToken;
    }

    @Override
    public void evictToken(String token) {
        AccessToken accessToken = checkToken(token);
        tokenCacheService.evict(token);
        long current = DateUtil.current();
        log.info("用户主动注销, 登录时间{}, 注销时间{}, 登录时长{}",
                DateUtil.format(new Date(accessToken.getCreateTime()), DATE_FORMAT),
                DateUtil.format(new Date(current), DATE_FORMAT),
                (current - accessToken.getCreateTime())/1000 + "秒");
    }

    private AccessToken checkToken(String token) {
        if (StrUtil.isBlankIfStr(token)) {
            log.debug("用户未登陆");
            throw new FundBizException(ResultCode.NO_LOGIN);
        }
        AccessToken accessToken = tokenCacheService.get(token);
        if (null == accessToken) {
            log.info("用户登陆校验失败,token {}, userId {}", token,
                    EncryptUtil.decrypt(token.substring(0, token.lastIndexOf("|"))));
            throw new FundBizException(ResultCode.LOGIN_EXPIRE);
        }
        return accessToken;
    }

}
